package utils

import (
	"context"
	"io"
	"time"

	"github.com/minio/minio-go/v7"
)

// MinioUtil 封装 MinIO 功能
type MinioUtil struct {
	Client     *minio.Client
	BucketName string
	Ctx        context.Context
}

// MinioTool 全局单例工具类
var MinioTool *MinioUtil

// ------------------------- 工具方法 -------------------------

// UploadFile 上传文件
func (m *MinioUtil) UploadFile(objectName string, reader io.Reader, size int64, contentType string) error {
	_, err := m.Client.PutObject(m.Ctx, m.BucketName, objectName, reader, size, minio.PutObjectOptions{
		ContentType: contentType,
	})
	return err
}

// DownloadFile 下载文件
func (m *MinioUtil) DownloadFile(objectName string) (io.ReadCloser, error) {
	obj, err := m.Client.GetObject(m.Ctx, m.BucketName, objectName, minio.GetObjectOptions{})
	if err != nil {
		return nil, err
	}
	return obj, nil
}

// DeleteFile 删除文件
func (m *MinioUtil) DeleteFile(objectName string) error {
	return m.Client.RemoveObject(m.Ctx, m.BucketName, objectName, minio.RemoveObjectOptions{})
}

// FileExists 判断文件是否存在
func (m *MinioUtil) FileExists(objectName string) (bool, error) {
	_, err := m.Client.StatObject(m.Ctx, m.BucketName, objectName, minio.StatObjectOptions{})
	if err != nil {
		if minio.ToErrorResponse(err).Code == "NoSuchKey" {
			return false, nil
		}
		return false, err
	}
	return true, nil
}

// PresignedURL 生成带过期时间的下载 URL
func (m *MinioUtil) PresignedURL(objectName string, expire time.Duration) (string, error) {
	url, err := m.Client.PresignedGetObject(m.Ctx, m.BucketName, objectName, expire, nil)
	if err != nil {
		return "", err
	}
	return url.String(), nil
}

// ListFiles 列出 bucket 下所有文件
func (m *MinioUtil) ListFiles(prefix string) ([]string, error) {
	var files []string
	opts := minio.ListObjectsOptions{
		Prefix:    prefix,
		Recursive: true,
	}
	for obj := range m.Client.ListObjects(m.Ctx, m.BucketName, opts) {
		if obj.Err != nil {
			return nil, obj.Err
		}
		files = append(files, obj.Key)
	}
	return files, nil
}

// GetFolderSize 获取某个目录下所有文件的总大小（字节数）
func (m *MinioUtil) GetFolderSize(prefix string) (int64, error) {
	var totalSize int64 = 0

	// 递归列出所有对象
	objectCh := m.Client.ListObjects(m.Ctx, m.BucketName, minio.ListObjectsOptions{
		Prefix:    prefix,
		Recursive: true,
	})

	for obj := range objectCh {
		if obj.Err != nil {
			return 0, obj.Err
		}
		totalSize += obj.Size
	}

	return totalSize, nil
}
